package com.duojuhe.common.utils.encryption.rsa;

import com.duojuhe.common.utils.encryption.base64.Base64Util;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

public class RSAUtilBig {
    /** */
    /**
     * 加密算法RSA
     */
    public static final String KEY_ALGORITHM = "RSA";

    /** */
    /**
     * 签名算法
     */
    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";

    /** */
    /**
     * 获取公钥的key
     */
    private static final String PUBLIC_KEY = "RSAPublicKey";

    /** */
    /**
     * 获取私钥的key
     */
    private static final String PRIVATE_KEY = "RSAPrivateKey";

    /** */
    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /** */
    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;

    /** */
    /**
     * <p>
     * 生成密钥对(公钥和私钥)
     * </p>
     *
     * @return
     * @throws Exception
     */
    public static Map<String, Object> genKeyPair() throws Exception {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        keyPairGen.initialize(1024);
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        Map<String, Object> keyMap = new HashMap<String, Object>(2);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /** */
    /**
     * <p>
     * 用私钥对信息生成数字签名
     * </p>
     *
     * @param data
     *            已加密数据
     * @param privateKey
     *            私钥(BASE64编码)
     *
     * @return
     * @throws Exception
     */
    public static String sign(byte[] data, String privateKey) throws Exception {
        byte[] keyBytes = Base64Util.decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(privateK);
        signature.update(data);
        return Base64Util.encode(signature.sign());
    }

    /** */
    /**
     * <p>
     * 校验数字签名
     * </p>
     *
     * @param data
     *            已加密数据
     * @param publicKey
     *            公钥(BASE64编码)
     * @param sign
     *            数字签名
     *
     * @return
     * @throws Exception
     *
     */
    public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
        byte[] keyBytes = Base64Util.decode(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey publicK = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(publicK);
        signature.update(data);
        return signature.verify(Base64Util.decode(sign));
    }

    /** */
    /**
     * <P>
     * 私钥解密
     * </p>
     *
     * @param encryptedData
     *            已加密数据
     * @param privateKey
     *            私钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception {
        byte[] keyBytes = Base64Util.decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateK);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }

    /** */
    /**
     * <p>
     * 公钥解密
     * </p>
     *
     * @param encryptedData
     *            已加密数据
     * @param publicKey
     *            公钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception {
        byte[] keyBytes = Base64Util.decode(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicK);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }

    /** */
    /**
     * <p>
     * 公钥加密
     * </p>
     *
     * @param data
     *            源数据
     * @param publicKey
     *            公钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
        byte[] keyBytes = Base64Util.decode(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicK);

        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;
    }

    /** */
    /**
     * <p>
     * 私钥加密
     * </p>
     *
     * @param data
     *            源数据
     * @param privateKey
     *            私钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception {
        byte[] keyBytes = Base64Util.decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;
    }

    /** */
    /**
     * <p>
     * 获取私钥
     * </p>
     *
     * @param keyMap
     *            密钥对
     * @return
     * @throws Exception
     */
    public static String getPrivateKey(Map<String, Object> keyMap) throws Exception {
        Key key = (Key) keyMap.get(PRIVATE_KEY);
        return Base64Util.encode(key.getEncoded());
    }

    /** */
    /**
     * <p>
     * 获取公钥
     * </p>
     *
     * @param keyMap
     *            密钥对
     * @return
     * @throws Exception
     */
    public static String getPublicKey(Map<String, Object> keyMap) throws Exception {
        Key key = (Key) keyMap.get(PUBLIC_KEY);
        return Base64Util.encode(key.getEncoded());
    }

    /**
     * java端公钥加密
     */
    public static String encryptPublic(String data, String PUBLICKEY) {
        try {
            data = Base64Util.encode(encryptByPublicKey(data.getBytes(), PUBLICKEY));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * java端私钥解密
     */
    public static String decryptPrivate(String data, String PRIVATEKEY) {
        String temp = "";
        try {
            byte[] rs = Base64Util.decode(data);
            temp = new String(decryptByPrivateKey(rs, PRIVATEKEY), StandardCharsets.UTF_8); //以utf-8的方式生成字符串

        } catch (Exception e) {
            e.printStackTrace();
        }
        return temp;
    }



    /**
     * java端私钥加密
     */
    public static String encryptPrivate(String data, String PRIVATEKEY) {
        try {
            data = Base64Util.encode(encryptByPrivateKey(data.getBytes(), PRIVATEKEY));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }


    /**
     * java端公钥解密
     */
    public static String decryptPublic(String data, String PUBLICKEY) {
        String temp = "";
        try {
            byte[] rs = Base64Util.decode(data);
            temp = new String(decryptByPublicKey(rs, PUBLICKEY), StandardCharsets.UTF_8); //以utf-8的方式生成字符串
        } catch (Exception e) {
            e.printStackTrace();
        }
        return temp;
    }

    public static void main(String[] args) throws Exception {
       Map<String, Object> map = genKeyPair();
        //String PUBLICKEY = getPublicKey(map);
        //String PRIVATEKEY = getPrivateKey(map);
       // System.out.println("PUBLIC_KEY:"+PUBLICKEY);
        //System.out.println("PRIVATE_KEY:"+PRIVATEKEY);
        //String PRIVATE_KEY = "MIICWgIBAAKBgF6vN22Y7TdXmniGOOJ/SD9jsLWCLntQdORBT3TzlnCMMGBN3RxIJSjW5cfQDBOEHLMo/Y8m4WynGcWDIZY/cjmNgP37jEdHcIYHIzwGVW4x7MlvREBHYXUfcOfGQMGMAD3Mhf+Ge0MoIp5YCsbLdMuk7Q/WVC9kprtjshdPRBWJAgMBAAECgYAVIp2HzFwfP2HOx39JJ8pTxAf87Ds98X62ONHotDr/knt188uIdZ492IJgMNORQ6s4Xs0CuFYXb9Fz4kqMBEuVwIWUvEJeElqpwA8f055uif35MSmfnOLc0F/4xf5DzlYD5N18/yobUUpXGZ0cci7uyiZcn90shohSOPLoJ8AMAQJBALuabDoTklfrnK0xbLlpXluEaQN8pD3yMuIU79N/0cSJTELK0lSBgFeb8dvas8o/8UJ8mTaHeQh6nQ1SNdP89gkCQQCBNGcPTrPEnXYju70EnBYhQvWjAubWlxw+gB6xVwQIdfodZxOQhgdIeToyXwq0bfjMFMCkog8s0kfJ+VCBGgOBAkA73VYl3jL3zV6swbXRILeUepdMHo0Gm2/zRv0Uv5f/oFRuh+xAPSboTgIKxypSIr9pGPuHNAnCU+Yj5xT4NaOJAkA498H5HdpldogAeWZ+AdRAFiX4Ge9t7nKlnBfsWVGN6Xa+QBSARJgxfEIMs5sksthgI0ZNUKcgPBcrFqJIShABAkAO6GF5Wh3buHhL8X0XtLToG14MEQ9f233C368nAjDkI8ZwYJjcof6cgx5pPuFoM4NVK7qyxteKfbA4DlILqOnm";

        //String PUBLIC_KEY = "MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgF6vN22Y7TdXmniGOOJ/SD9jsLWCLntQdORBT3TzlnCMMGBN3RxIJSjW5cfQDBOEHLMo/Y8m4WynGcWDIZY/cjmNgP37jEdHcIYHIzwGVW4x7MlvREBHYXUfcOfGQMGMAD3Mhf+Ge0MoIp5YCsbLdMuk7Q/WVC9kprtjshdPRBWJAgMBAAE=";
     /*   Map<String, Object> map = genKeyPair();
        String PUBLIC_KEY = getPublicKey(map);
        String PRIVATE_KEY = getPrivateKey(map);
        String data = "256";
        //私钥加密
        System.out.println(new String(encryptByPrivateKey(data.getBytes(),PRIVATE_KEY)));
        //公钥解密
        System.out.println(decryptByPublicKey(encryptByPrivateKey(data.getBytes(),PRIVATE_KEY),PUBLIC_KEY));*/


        //公钥加密
        //System.out.println(encryptByPublicKey(data,PUBLIC_KEY));
        //私钥解密
        //System.out.println(decryptByPrivateKey(encryptByPublicKey(data,PUBLIC_KEY),PRIVATE_KEY));

        //String PUBLICKEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCcd+0zTY9Gn94iqkQJTlxYnEnCeFsLkk0a7hoAvi2B74VzDVV3xH0ZO9RkXvo1SgCB+uzbEWdrgQkzTqyjfTtgOguu3OnkVxIMJF34ibchTY0LWHGxq1m2gLGuVVqrlu1LtdV0X7xo/5zc8Mr+46veWb86kSpqe6rOAm69WWo5GwIDAQAB";
        //String PRIVATEKEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJx37TNNj0af3iKqRAlOXFicScJ4WwuSTRruGgC+LYHvhXMNVXfEfRk71GRe+jVKAIH67NsRZ2uBCTNOrKN9O2A6C67c6eRXEgwkXfiJtyFNjQtYcbGrWbaAsa5VWquW7Uu11XRfvGj/nNzwyv7jq95ZvzqRKmp7qs4Cbr1ZajkbAgMBAAECgYAHp349EkA+DjgJrhah9elilFKvZr/dcwy+koNHIgaL4rG+jRpvP3d3MowTVOocjUA1G5dWqCVNBwTyM5kSbl/nIxSCYwdUoDid4r0JbqkXkTTsIq3euHG8eiWr9rr3SDmwDojWoJEc4liVlfme8dQuMfgxe1QKq7wTrJwCKwbeMQJBAPwpknRPRK8W9hefbbtEu8mlbzUy+ER8Puq6dvS+lnWzJ8n2chJcHRYQFwWpjl4+SZuKeEcDmYmuQ7xuqEIayO0CQQCe2YeaxcU4uuDC45RAwCcMaNw1nDJuA+Gi47lXbroBXoeOiNZunViSZVUgDgrV/Ku6V54TaZIzZ21QFjf7mXEnAkEA7dZwMpAJonOvzfwrzbQ4wyrsx2q5zC68UT1qsdGJrJ48azutwC9tp7+pV0fj5nQtjS1/4Ms+aCQb84ET5rXIyQJAM0m45tgEHZT5DPO94kooUXFp6EVOYwcNyzILnZc6p0aGLhcwZPaYqmvdWEQwa3bxW3D+sPXdJou2V61U1f9s8QJALccvYwwWlCTq1iTmegYk9fOoc+isZKH+Z0YW70kFi94AYEO+utYwmXBEAqQ5VC/bywa1O71xdL4/RGCOSxBf2A==";
        //String PRIVATEKEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKbrsRw7J/Ib+2IdLciK/OavGK/GyYI1gLPmVdYRo0uzDLvWQ0ZLCDLn5Voqhe2CXFuwA8oe0Xj8gYB7S9IqYMYBw5043LAc/+esphiw7WGExjHpTrK1LSA25/pxnCAySF/klm+U2+I0GHTz3M3VarY6oGk7DxxZe0+It/V+515rAgMBAAECgYEAmghzZsbcJNpXjwG4JxDDMikwUbzSZTr0Ko8KdMHP++IdhRTC/hHtXfSKvDrzXepnSiDSTmlECi6RXrvoiueaZoBhVI09c7HNgVC6nT2R4CykbA8DId6TNxl5WMNPEE/SFOK6gYg6XyriKGvRtb4X8tWmicEXPNCXga0BkLTWaskCQQDZq898Jtr0HFEvJcSUtyJ1z5wI77jGKTCICJBxV2si0HOV9oE9vXmkAZy/x+xsXnmO6NNra9nfjmuCSH9Va4w9AkEAxFAmTEB0p4Xk0SMxo9ZRn0xK5S3MMnoAKd2DL0kDi5QpqlxnpZyqNip67u0fJTx49YSlytMoGMsScTQlQ2F3xwJAD57Lue4T4lax4L9GFyH5QBkQ6ndBfD7yc6ChtPCACLSKxuU0qxiQxRs0g3K2XaR99qpwmZHYxbkzr9rCAIBCRQJBALGzB2fAdJfrmFtDKzzt1EaI7caT9SG/04QR8hyMT/w5qpl+OYfszxpmy46Y77dqDOfZIaX+C26d61yzYgOjJ6MCQAone04IWkopCVBy4x/ceowykUiVFqf/Otg4vSYz2n0JCsslOvkZy6x5r2d91c37VeMiXuwhVQzlANJ3WyfXi7g=";
        //String PUBLICKEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCm67EcOyfyG/tiHS3IivzmrxivxsmCNYCz5lXWEaNLswy71kNGSwgy5+VaKoXtglxbsAPKHtF4/IGAe0vSKmDGAcOdONywHP/nrKYYsO1hhMYx6U6ytS0gNuf6cZwgMkhf5JZvlNviNBh089zN1Wq2OqBpOw8cWXtPiLf1fudeawIDAQAB";

        String PRIVATEKEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJyYYubwPG0gCF61Y6Vy5hBe8tNPeir1VOBI0VN5EgJI10xfhPizII5YqmoQffFnL9FG5VXZ9gIH5JOaLiQl4i/YU9bm15yNQaSaBOIVKA8lDtL3CbBrSMOSNM6m2HPDNlaMVysItXXagGEFfq8JCVCJmSgIuaB4Fz4lZ5ibfPOBAgMBAAECgYBEd2QWsMbat3yxXAF7Xycz1S+6MC+sBKPdhDjxlCfJk+t+Wu0ah8ceNaocwaUvHPyNNcAjry6eaLEJ0AmIiH/B1xk6Gg8WP/Lf24SG5OKM0MXoRWhY9vCHnrgv2BOhFH3Z6uZ5K4PDN500sQIcVMUwZLM/dTzvBFRUCNCYw2wYGQJBAOKS/yiILPq+PJ/MAhq4LsQKnxxXVFYVvdG7wm0zybhsRqLduJm3pCjIW/NjbLPGf2vWNnBKzISG+D/SBir4sYsCQQCw7sWGKEQAACWcX8VJxwqAMLQMSzPLyGEMSj7YCHdwGDb3LQqQnIT0hlxkOOibrztPFNVAeznux9u2ekXfmLijAkEAvVjdVhEfjdjHrz99jrjXlEvQFo5A08RNouYHoN1DuhT6nwcuS4A190Mh3O/9GuxK9mLJkeRgsGxfMG6jauv06wJAY64BhjWFKeLrTY//HDOQzOujZBGyGqrHUh86DIeoknRx8wtjGlmz5fcUcjpFggBVD5aTFgLWfpoGRGXam7/0tQJAc9Zf6h1s1iwVaLCkj2kGN6NwRUnty9sRpiuEfSP3VhHtUQhNDlhkF7OX9IWQTiyXnH7hORmIbhL6vdudOAtvEw==";
        String PUBLICKEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCcmGLm8DxtIAhetWOlcuYQXvLTT3oq9VTgSNFTeRICSNdMX4T4syCOWKpqEH3xZy/RRuVV2fYCB+STmi4kJeIv2FPW5tecjUGkmgTiFSgPJQ7S9wmwa0jDkjTOpthzwzZWjFcrCLV12oBhBX6vCQlQiZkoCLmgeBc+JWeYm3zzgQIDAQAB";


        String data = "df723820";
       data = encryptPublic(data, PUBLICKEY);
       System.out.println("公加密数据：" + data);
       System.out.println("私解密数据：" + decryptPrivate(data, PRIVATEKEY));


      String data1 = "df723820";
       data1 = encryptPrivate(data1, PRIVATEKEY);
       System.out.println("私加密数据：" + data);

      System.out.println("公解密数据：" + decryptPublic(data1,PUBLICKEY));

      System.out.println("公解密数据：" + decryptPublic(new String(Base64Util.encode(encryptByPrivateKey("df723820".getBytes(), PRIVATEKEY))),PUBLICKEY));
      System.out.println("公解密数据：" + new String(decryptByPublicKey(encryptByPrivateKey("df723820".getBytes(), PRIVATEKEY),PUBLICKEY)));
    }

}
